//
// Created by cktor on 2017/8/16.
//

#include "cn_w_NetInfoConfig.h"

#include <sys/types.h>
#include <string.h>
#include <stdlib.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <sys/utsname.h>
#include <ctype.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <net/if.h>
#include <linux/sockios.h>
#include <net/route.h>
#include <fcntl.h>
#include <sys/wait.h>

#include <jni.h>

#include <android/log.h>

#define IFNAME "eth0"

static int charToInt(char *charArray);

#ifndef DBG_LEVEL
#define DBG_LEVEL 5
#endif

#ifndef LOG
#define LOG "NetInfoConfig"
#endif

#ifndef LOGE
#define LOGE(...)  __android_log_print(ANDROID_LOG_ERROR,LOG,__VA_ARGS__) // 定义LOGE类型
#endif

static int charToInt(char *charArray) {
    return charArray[0] << 24 | charArray[1] << 16 | charArray[2] << 8 | charArray[3];
}

typedef struct NetInfo {
    char ipAddr[4];
    char subnetMask[4];
    char gateway[4];
    char macAddr[6];
} NET_INFO;

int _setNetInfo_(const char *netInfo, int netInfoLength);

int _setIpInfo_(const char *netInfo, int netInfoLength);

/*
 * Class:     cn_cktor_android_jni_ip_NetInfoConfig
 * Method:    setIpAddrAndMask
 * Signature: ([BI)I
 */
JNIEXPORT jint

JNICALL Java_cn_w_NetInfoConfig_setNetInfo
        (JNIEnv *env, jobject obj, jbyteArray _netInfo, jint _netInfoLength) {
    char *netInfo = (char *) (*env)->GetByteArrayElements(env, _netInfo, NULL);
    int returnValue = _setNetInfo_(netInfo, _netInfoLength);
    (*env)->ReleaseByteArrayElements(env, _netInfo, (jchar *) netInfo, 0);
    return returnValue;
//    return 0;
}


JNIEXPORT jint
JNICALL Java_cn_w_NetInfoConfig_setIpInfo
        (JNIEnv *env, jobject obj, jbyteArray _netInfo, jint _netInfoLength) {
    char *netInfo = (char *) (*env)->GetByteArrayElements(env, _netInfo, NULL);
    int returnValue = _setIpInfo_(netInfo, _netInfoLength);
    (*env)->ReleaseByteArrayElements(env, _netInfo, (jchar *) netInfo, 0);
    return returnValue;
}

int _setIpInfo_(const char *ipCharArray, int arrayLen) {

    LOGE("设置本机IP地址信息\n");

    if (arrayLen < 12) {
        LOGE("数据长度不正确");
        return -1;
    }

    int fd;
    int rc;
    struct ifreq ifr;
    struct sockaddr_in *sin;
    struct rtentry rt;

    unsigned char *ipAddr = ((NET_INFO *) ipCharArray)->ipAddr;
    unsigned char *subnetMask = ((NET_INFO *) ipCharArray)->subnetMask;

    unsigned char *gateway = ((NET_INFO *) ipCharArray)->gateway;

    fd = socket(AF_INET, SOCK_DGRAM, 0);

    LOGE("socket(AF_INET, SOCK_DGRAM, 0):%d\n", fd);
    if (fd < 0) {
        LOGE("socket error\n");
        return -1;
    }

    memset(&ifr, 0, sizeof(ifr));
    strcpy(ifr.ifr_name, IFNAME);

    sin = (struct sockaddr_in *) &ifr.ifr_addr;
    sin->sin_family = AF_INET;

    sin->sin_addr.s_addr = htonl(charToInt(ipAddr));
    int result = ioctl(fd, SIOCSIFADDR, &ifr);
    if (result < 0) {
        LOGE("%s:设置IP地址 %s 失败 %d\n", IFNAME, result, inet_ntoa(sin->sin_addr));
    }
    sin->sin_addr.s_addr = htonl(charToInt(subnetMask));
    if (ioctl(fd, SIOCSIFNETMASK, &ifr) < 0) {
        LOGE("%s:设置网络掩码失败\n", IFNAME);
    }

    //设置MAC地址先要关掉网络接口
//    ioctl(fd, SIOCGIFFLAGS, &ifr);
//    ifr.ifr_flags &= ~IFF_UP;
//    ioctl(fd, SIOCSIFFLAGS, &ifr);
//
//    ioctl(fd, SIOCGIFHWADDR, &ifr);
//    memcpy(ifr.ifr_hwaddr.sa_data, macAddr, 6);
//    if (ioctl(fd, SIOCSIFHWADDR, &ifr) < 0) {
//        LOGE("%s:设置MAC地址失败\n", IFNAME);
//    }
//
//    ioctl(fd, SIOCGIFFLAGS, &ifr);
//    ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
//    if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) {
//        LOGE("%s:启动网络失败\n", IFNAME);
//    } else {
//        LOGE("%s:启动网络成功\n", IFNAME);
//    }

    if ((charToInt(ipAddr) ^ charToInt(gateway)) & charToInt(subnetMask)) {
        LOGE("%s:网关和IP地址不在一个子网\n", IFNAME);
    }

    memset(&rt, 0, sizeof(struct rtentry));
    memset(sin, 0, sizeof(struct sockaddr_in));
    sin->sin_family = AF_INET;
    sin->sin_port = 0;
    sin->sin_addr.s_addr = htonl(charToInt(gateway));
    memcpy(&rt.rt_gateway, sin, sizeof(struct sockaddr_in));
    ((struct sockaddr_in *) &rt.rt_dst)->sin_family = AF_INET;
    ((struct sockaddr_in *) &rt.rt_genmask)->sin_family = AF_INET;
    rt.rt_flags = RTF_GATEWAY;
    if (ioctl(fd, SIOCADDRT, &rt) < 0) {
        LOGE("ioctl(SIOCADDRT) error in set_default_route\n");
        close(fd);
        return -1;
    }
    return 0;
}

int _setNetInfo_(const char *ipCharArray, int arrayLen) {

    LOGE("设置本机IP地址信息\n");

    if (arrayLen < 18) {
        LOGE("数据长度不正确");
        return -1;
    }

    int fd;
    int rc;
    struct ifreq ifr;
    struct sockaddr_in *sin;
    struct rtentry rt;

    unsigned char *ipAddr = ((NET_INFO *) ipCharArray)->ipAddr;
    unsigned char *subnetMask = ((NET_INFO *) ipCharArray)->subnetMask;

    unsigned char *gateway = ((NET_INFO *) ipCharArray)->gateway;
    unsigned char *macAddr = ((NET_INFO *) ipCharArray)->macAddr;

    fd = socket(AF_INET, SOCK_DGRAM, 0);

    LOGE("socket(AF_INET, SOCK_DGRAM, 0):%d\n", fd);
    if (fd < 0) {
        LOGE("socket error\n");
        return -1;
    }

    memset(&ifr, 0, sizeof(ifr));
    strcpy(ifr.ifr_name, IFNAME);

    sin = (struct sockaddr_in *) &ifr.ifr_addr;
    sin->sin_family = AF_INET;

    sin->sin_addr.s_addr = htonl(charToInt(ipAddr));
    int result = ioctl(fd, SIOCSIFADDR, &ifr);
    if (result < 0) {
        LOGE("%s:设置IP地址 %s 失败 %d\n", IFNAME, result, inet_ntoa(sin->sin_addr));
    }
    sin->sin_addr.s_addr = htonl(charToInt(subnetMask));
    if (ioctl(fd, SIOCSIFNETMASK, &ifr) < 0) {
        LOGE("%s:设置网络掩码失败\n", IFNAME);
    }

    //设置MAC地址先要关掉网络接口
    ioctl(fd, SIOCGIFFLAGS, &ifr);
    ifr.ifr_flags &= ~IFF_UP;
    ioctl(fd, SIOCSIFFLAGS, &ifr);

    ioctl(fd, SIOCGIFHWADDR, &ifr);
    memcpy(ifr.ifr_hwaddr.sa_data, macAddr, 6);
    if (ioctl(fd, SIOCSIFHWADDR, &ifr) < 0) {
        LOGE("%s:设置MAC地址失败\n", IFNAME);
    }

    ioctl(fd, SIOCGIFFLAGS, &ifr);
    ifr.ifr_flags |= IFF_UP | IFF_RUNNING;
    if (ioctl(fd, SIOCSIFFLAGS, &ifr) < 0) {
        LOGE("%s:启动网络失败\n", IFNAME);
    } else {
        LOGE("%s:启动网络成功\n", IFNAME);
    }

    if ((charToInt(ipAddr) ^ charToInt(gateway)) & charToInt(subnetMask)) {
        LOGE("%s:网关和IP地址不在一个子网\n", IFNAME);
    }

    memset(&rt, 0, sizeof(struct rtentry));
    memset(sin, 0, sizeof(struct sockaddr_in));
    sin->sin_family = AF_INET;
    sin->sin_port = 0;
    sin->sin_addr.s_addr = htonl(charToInt(gateway));
    memcpy(&rt.rt_gateway, sin, sizeof(struct sockaddr_in));
    ((struct sockaddr_in *) &rt.rt_dst)->sin_family = AF_INET;
    ((struct sockaddr_in *) &rt.rt_genmask)->sin_family = AF_INET;
    rt.rt_flags = RTF_GATEWAY;
    if (ioctl(fd, SIOCADDRT, &rt) < 0) {
        LOGE("ioctl(SIOCADDRT) error in set_default_route\n");
        close(fd);
        return -1;
    }
    return 0;
}
